﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;

namespace FBGraph.ClientGenerator.CodeGen
{
    public class TypeReference : CodeGenObject
    {
        public TypeReference(CodeGenType type)
            : this(type.Name, type.TypeArguments)
        {
            this.GeneratedType = type;
        }

        public TypeReference(Type type)
            : this(type.Name.Split('`')[0], type.GetGenericArguments().Where(a => !a.IsGenericParameter).Select(a => new TypeReference(a)).ToArray()) { this.Type = type; }

        public TypeReference(Type type, params TypeReference[] typeArguments)
            : this(type.Name.Split('`')[0], typeArguments)
        {
            if (type.IsGenericTypeDefinition && typeArguments.All(t => t.Type != null))
            {
                type = type.MakeGenericType(typeArguments.Select(t => t.Type).ToArray());
            }
            
            this.Type = type;
        }

        public TypeReference(String name, params TypeReference[] typeArguments)
            : this(name, new TypeArgumentsList(typeArguments)) { }

        public TypeReference(String name, TypeArgumentsList typeArguments)
        {
            this.Name = name;
            this.TypeArguments = typeArguments ?? new TypeArgumentsList();
        }

        public String Name { get; set; }
        public TypeArgumentsList TypeArguments { get; private set; }
        public Boolean IsGeneratedType { get { return this.GeneratedType != null; } }
        public Type Type { get; private set; }
        public CodeGenType GeneratedType { get; private set; }

        public override void Write(CodeGenWriter writer)
        {
            writer.Write(this.Name);
            writer.Write(this.TypeArguments);
        }

        public override Boolean Equals(Object obj)
        {
            var that = obj as TypeReference;
            if (that == null) return false;
            else return
                this.Name == that.Name &&
                this.TypeArguments.SequenceEqual(that.TypeArguments);
        }

        public override Int32 GetHashCode()
        {
            return
                this.Name.GetHashCode() ^
                this.TypeArguments.GetHashCode();
        }
    }
}